﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace WyUnity.Utility.ExtentionMethods
{
	/// <summary>
	/// IEnumerable extensions
	/// </summary>
	public static class IEnumerableExtensions
	{
		#region Functions

		#region Exists

		/// <summary>
		/// 判定IEnumerable&lt;T&gt;中是否存在某个项目
		/// </summary>
		public static bool Exists<T>(this IEnumerable<T> list, Predicate<T> match)
		{
			match.ThrowIfNull("Match");
			if (list == null)
				return false;
			foreach (T Item in list)
			{
				if (match(Item))
					return true;
			}
			return false;
		}

		#endregion

		#region For

		/// <summary>
		/// 循环IEnumerable&lt;T&gt;对象
		/// </summary>
		public static IEnumerable<T> For<T>(this IEnumerable<T> list, int start, int end, Action<T> action)
		{
			list.ThrowIfNull("List");
			action.ThrowIfNull("Action");
			int x = 0;
			foreach (T item in list)
			{
				if (x.Between(start, end))
					action(item);
				++x;
				if (x > end)
					break;
			}
			return list;
		}

		/// <summary>
		/// 循环IEnumerable&lt;T&gt;对象，返回IEnumerable&lt;T&gt;结果
		/// </summary>
		public static IEnumerable<R> For<T, R>(this IEnumerable<T> list, int start, int end, Func<T, R> function)
		{
			list.ThrowIfNull("List");
			function.ThrowIfNull("Function");
			int x = 0;
			List<R> returnValues = new List<R>();
			foreach (T Item in list)
			{
				if (x.Between(start, end))
					returnValues.Add(function(Item));
				++x;
				if (x > end)
					break;
			}
			return returnValues;
		}

		#endregion

		#region ForEach

		/// <summary>
		/// 遍历IEnumerable&lt;T&gt;中的每一个项目
		/// </summary>
		public static IEnumerable<T> ForEach<T>(this IEnumerable<T> list, Action<T> action)
		{
			list.ThrowIfNull("List");
			action.ThrowIfNull("Action");
			foreach (T Item in list)
				action(Item);
			return list;
		}

		/// <summary>
		/// 遍历IEnumerable&lt;T&gt;中的每一个项目，返回结果
		/// </summary>
		public static IEnumerable<R> ForEach<T, R>(this IEnumerable<T> list, Func<T, R> function)
		{
			list.ThrowIfNull("List");
			function.ThrowIfNull("Function");
			List<R> ReturnValues = new List<R>();
			foreach (T Item in list)
				ReturnValues.Add(function(Item));
			return ReturnValues;
		}

		#endregion

		#region ForParallel

		/// <summary>
		/// 并行遍历IEnumerable&lt;T&gt;中的部分项目，返回原始IEnumerable&lt;T&gt;
		/// 
		/// </summary>
		public static IEnumerable<T> ForParallel<T>(this IEnumerable<T> list, int start, int end, Action<T> action)
		{
			list.ThrowIfNull("List");
			action.ThrowIfNull("Action");
			Parallel.For(start, end + 1, new Action<int>(x => action(list.ElementAt(x))));
			return list;
		}

		/// <summary>
		/// 并行遍历IEnumerable&lt;T&gt;中的部分项目，返回结果
		/// </summary>
		public static IEnumerable<R> ForParallel<T, R>(this IEnumerable<T> list, int start, int end, Func<T, R> function)
		{
			list.ThrowIfNull("List");
			function.ThrowIfNull("Function");
			R[] results = new R[(end + 1) - start];
			Parallel.For(start, end + 1, new Action<int>(x => results[x - start] = function(list.ElementAt(x))));
			return results;
		}

		#endregion

		#region ForEachParallel

		/// <summary>
		/// 并行遍历IEnumerable&lt;T&gt;中的所有项目，返回原始IEnumerable&lt;T&gt;
		/// </summary>
		public static IEnumerable<T> ForEachParallel<T>(this IEnumerable<T> list, Action<T> action)
		{
			list.ThrowIfNull("List");
			action.ThrowIfNull("Action");
			Parallel.ForEach(list, action);
			return list;
		}

		/// <summary>
		/// 并行遍历IEnumerable&lt;T&gt;中的所有项目，返回结果
		/// </summary>
		public static IEnumerable<R> ForEachParallel<T, R>(this IEnumerable<T> list, Func<T, R> function)
		{
			list.ThrowIfNull("List");
			function.ThrowIfNull("Function");
			return list.ForParallel(0, list.Count() - 1, function);
		}

		#endregion

		#region IsNullOrEmpty

		/// <summary>
		/// 判断IEnumerable&lt;T&gt;是否为Null或者没有元素
		/// </summary>
		public static bool IsNullOrEmpty<T>(this IEnumerable<T> value)
		{
			return value == null || value.Count() == 0;
		}

		#endregion

		#region RemoveDefaults

		/// <summary>
		/// 从列表中移除默认值
		/// </summary>
		public static IEnumerable<T> RemoveDefaults<T>(this IEnumerable<T> value, IEqualityComparer<T> equalityComparer = null)
		{
			if (value == null)
				yield break;
			equalityComparer = equalityComparer.NullCheck(new GenericEqualityComparer<T>());
			foreach (T item in value.Where(x => !equalityComparer.Equals(x, default(T))))
				yield return item;
		}

		#endregion

		#region ToArray

		/// <summary>
		/// 将列表转换为数组
		/// </summary>
		public static Target[] ToArray<Source, Target>(this IEnumerable<Source> list, Func<Source, Target> convertingFunction)
		{
			list.ThrowIfNull("List");
			convertingFunction.ThrowIfNull("ConvertingFunction");
			return list.ForEach(convertingFunction).ToArray();
		}

		#endregion

		#region ToString

		/// <summary>
		/// 将列表转换为字符串
		/// </summary>
		public static string ToString<T>(this IEnumerable<T> list, Func<T, string> itemOutput = null, string seperator = ",")
		{
			list.ThrowIfNull("List");
			seperator = seperator.NullCheck("");
			itemOutput = itemOutput.NullCheck(x => x.ToString());
			StringBuilder builder = new StringBuilder();
			string tempSeperator = "";
			list.ForEach(x =>
			{
				builder.Append(tempSeperator).Append(itemOutput(x));
				tempSeperator = seperator;
			});
			return builder.ToString();
		}

		#endregion

		#region TrueForAll

		/// <summary>
		/// 判断列表中是否每一项都满足条件
		/// </summary>
		public static bool TrueForAll<T>(this IEnumerable<T> list, Predicate<T> predicate)
		{
			list.ThrowIfNull("List");
			predicate.ThrowIfNull("Predicate");
			return !list.Any(x => !predicate(x));
		}

		#endregion

		#region TryAll

		/// <summary>
		/// 尝试对列表的每一项执行一个action操作，如果发生异常，则执行catchAction操作
		/// </summary>
		public static IEnumerable<T> TryAll<T>(this IEnumerable<T> list, Action<T> action, Action<T> catchAction = null)
		{
			list.ThrowIfNull("List");
			action.ThrowIfNull("Action");
			foreach (T item in list)
			{
				try
				{
					action(item);
				}
				catch { if (catchAction != null) catchAction(item); }
			}
			return list;
		}

		#endregion

		#region TryAllParallel

		/// <summary>
		/// 尝试对列表的每一项执行一个action操作，如果发生异常，则执行catchAction操作
		/// 这里将会以并行的方式执行。
		/// </summary>
		public static IEnumerable<T> TryAllParallel<T>(this IEnumerable<T> list, Action<T> action, Action<T> catchAction = null)
		{
			list.ThrowIfNull("List");
			action.ThrowIfNull("Action");
			Parallel.ForEach<T>(list, delegate(T Item)
			{
				try
				{
					action(Item);
				}
				catch { if (catchAction != null) catchAction(Item); }
			});
			return list;
		}

		#endregion

		public static IEnumerable<R> ConvertAll<T, R>(this IEnumerable<T> list, Func<T, R> convertMethod)
		{
			return list.ForEach(convertMethod);
		}

		#endregion
	}
}
